---
title: Security
description: Learn about security headers and how to configure them for your app.
---

import {
  Aside,
  Tabs,
  TabItem,
  LinkCard,
  Code,
} from "@astrojs/starlight/components";

## 🔐 Security Headers

Security headers are an important part of protecting your application from common attacks like cross-site scripting (XSS), clickjacking, and data injection. RedwoodSDK makes it easy to add these headers to your responses using middleware.

Here is an example of a middleware that adds a set of common security headers:

```typescript title="src/app/headers.ts"
import type { RouteMiddleware } from "rwsdk/worker";

export const setCommonHeaders =
  (): RouteMiddleware =>
  ({ response, rw: { nonce } }) => {
    const headers = response.headers;
    headers.set("X-Frame-Options", "DENY");
    headers.set("X-Content-Type-Options", "nosniff");
    headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
    headers.set(
      "Content-Security-Policy",
      `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; object-src 'none';`
    );
    headers.set(
      "Permissions-Policy",
      "geolocation=(), microphone=(), camera=()"
    );
  };
```

You can then apply this middleware in your `src/worker.tsx`:

```typescript title="src/worker.tsx"
import { rwsdk } from "rwsdk/worker";
import { setCommonHeaders } from "./app/headers.js";
import { routes } from "./app/pages/routes.js";

export default {
  async fetch(request, env, ctx) {
    return rwsdk(request, env, ctx, {
      routes,
      middleware: [setCommonHeaders()],
    });
  },
};
```

### Changing CSP (Content Security Policy) headers

Sometimes you need to allow additional resources or modify the Content Security Policy (CSP) to accommodate third-party scripts, styles, or other assets. The CSP headers control what resources can be loaded and executed by your application.

#### Adding trusted domains

<Aside>
  Your CSP should reflect your application's needs. Some apps require more
  permissive policies to function properly, while security-critical applications
  might need stricter controls. The key is understanding the tradeoffs and
  making informed decisions. For more information, see the [MDN Content Security
  Policy documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
</Aside>

```diff
// In app/headers.ts
headers.set(
  "Content-Security-Policy",
- `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; object-src 'none';`,
+ `default-src 'self'; script-src 'self' 'nonce-${nonce}' https://trusted-scripts.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' https://images.example.com; object-src 'none';`,
);
```

#### Allowing images from multiple sources

When working with images in your RedwoodSDK application, you may need to load images from different sources such as remote URLs or data URIs. The default CSP configuration doesn't include an `img-src` directive, which means images from external sources will be blocked.

To allow images from remote URLs and data URIs, add the `img-src` directive to your CSP:

```diff
// In app/headers.ts
headers.set(
  "Content-Security-Policy",
- `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; object-src 'none';`,
+ `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; img-src 'self' https://trusted-images.example.com data:; object-src 'none';`,
);
```

This configuration allows:

- `'self'` - Images from your own domain
- `https://trusted-images.example.com` - Images from specific trusted domains
- `data:` - Data URIs (base64 encoded images)

<Aside type="caution">
  Be cautious when using `data:` URIs as they can significantly increase the
  size of your HTML. Only allow specific remote domains that you trust, and
  consider using a more restrictive CSP in production environments.
</Aside>

#### Using `nonce` for inline scripts

Sometimes you need to include inline scripts in your application, but Content Security Policy (CSP) blocks them by default for security reasons. RedwoodSDK automatically generates a fresh, cryptographically secure nonce value for each request You can access this nonce in document or page components rendered by the [router](./routing), using `rw.nonce`.

<Aside type="caution">
  Only use the nonce attribute for trusted inline scripts that you have full
  control over. Adding nonces to third-party or user-generated scripts defeats
  the purpose of CSP protection and could expose your application to cross-site
  scripting (XSS) attacks.
</Aside>

```tsx
export const Document = ({ rw, children }) => (
  <html lang="en">
    <head><!-- ... --></head>
    <body>
      <div id="root">{children}</div>

      <!-- Set the nonce the inline script -->
      <script nonce={rw.nonce}>/* ... */</script>
    </body>
  </html>
);
```

### Lifting device permission restrictions

Sometimes you need to allow your web application to access device features like the camera, microphone, or geolocation. These permissions are controlled by the `Permissions-Policy` header.

To enable device access, you'll need to modify the `Permissions-Policy` header in your `app/headers.ts` file:

```diff
// In app/headers.ts
headers.set(
  "Permissions-Policy",
-  "geolocation=(), microphone=(), camera=()",
+  "geolocation=self, microphone=self, camera=self"
);
```

The `self` keyword allows the feature to be used only by your own domain.

For a complete reference, see the [MDN Permissions Policy documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy).
